import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import momo.app.multicast.Msg;
import momo.app.multicast.MsgRcvListener;
import momo.app.multicast.MulticastComm;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class PlanetLabApp implements MsgRcvListener{
	
	private Log log = LogFactory.getLog("PlanetLabLog");
	
	private final String MY_ID = "myid";
	private final String MY_PORT = "myport";
	private final String CONNECTION_NODE = "connectionnode";
	private final String CONNECTION_PORT = "connectionport";
	private final String SEND_DELAY = "senddelay";
	private final String SEND_FILE = "sendfile";
	private final String INIT_SLEEP = "initsleep";
	
	final private String configFile = "config.txt";
	private Properties prop;
	private boolean isConfigLoaded;
	
	private String myId = "";
	private String connectionNode = "";
	private int connectionPort;
	private int myPort;
	private int sendDelay;
	private int initSleep;
	private String sendFile = "";
	private String fileContents = "";
	private Map<String, Double> costMap = new LinkedHashMap<String, Double>();
	
	private MulticastComm comm;
	
	public PlanetLabApp() {
		prop = new Properties();
		isConfigLoaded = false;
	}
	
	public void loadConfig(boolean noSleep) throws Exception {
		try {
			prop.load(new FileReader(new File(configFile)));
			myId = prop.getProperty(MY_ID);
			myPort = Integer.parseInt( prop.getProperty(MY_PORT) );
			connectionNode = prop.getProperty(CONNECTION_NODE);
			connectionPort = Integer.parseInt( prop.getProperty(CONNECTION_PORT) );
			sendDelay = getSendDelay(myId);
			initSleep = getInitSleep(myId);
			if (noSleep)
				initSleep = 0;
			sendFile = prop.getProperty(SEND_FILE);
			fileContents = getFileContents(sendFile);
			getCostMap(myId);
			
			isConfigLoaded = true;
		}catch (Exception e) {
			log.error(e);
			throw e;
		}
		
	}
	
	private int getSendDelay(String id) {
		double slpTime = Double.valueOf( prop.getProperty(SEND_DELAY+","+id) );
		return (int)(slpTime * 1000);
	}
	
	private int getInitSleep(String id) {
		double slpTime = Double.valueOf( prop.getProperty(INIT_SLEEP+","+id) );
		return (int)(slpTime * 1000);
	}
	
	private void getCostMap(String id) {
		Set<String> propTitles = prop.stringPropertyNames();
		for ( String propTitle: propTitles ) {
			if ( propTitle.indexOf("cost,"+id+",") == 0 ) {
				String sourceId = propTitle.substring( propTitle.lastIndexOf(",") + 1 );
				double cost = Double.valueOf( prop.getProperty(propTitle) );
				costMap.put(sourceId, cost);
			}
		}
	}
	
	private String getFileContents(String filename) throws Exception {
		StringBuffer buffer = new StringBuffer();
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String line = "";
		while ( (line=in.readLine()) != null ) {
			buffer.append( line + "\n" );
		}
		
		if ( buffer.length() > 0 )
			return buffer.substring( 0, buffer.length()-2 );
		else
			return buffer.toString();
	}
	
	public void displayConfig() {
		if ( isConfigLoaded ) {
			if ( log.isDebugEnabled() ) {
				log.debug("myId: " + myId);
				log.debug("myPort: " + myPort);
				log.debug("connectionNode: " + connectionNode);
				log.debug("connectionPort: " + connectionPort);
				log.debug("sendDelay: " + sendDelay);
				log.debug("initSleep: " + initSleep);
				log.debug("sendFile: " + sendFile);
				log.debug("fileContents: " + fileContents);
				for( String sourceId : costMap.keySet() )
					log.debug("Cost to "+sourceId+": " + costMap.get(sourceId));
			}
		}
	}
	
	public void runApp() throws Exception {
		
		if ( log.isDebugEnabled() )
			log.debug("sleeping for:"+initSleep);
		
		Thread.sleep(initSleep);
		comm = new MulticastComm(myId, myPort+1, myPort);
		comm.addMsgRcvListener(this);
		comm.setUserCost(costMap);
		if ( myId.equals( connectionNode ) )
			connectionNode = "";
		comm.connect(connectionNode, connectionPort);
		send();
	}
	
	private void send() {
		Thread t = new Thread()
		{
			public void run()
			{
				try
				{
					while ( true ) {
						sleep(sendDelay);
						comm.send(fileContents);
					}
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		t.start();
	}
	
	@Override
	public void msgLost(Map<String, Set<Integer>> lostMsg) {
	}

	@Override
	public void msgReceived(Msg msg) {
	}
	
	public static void main(String args[]) {
			try {
				PlanetLabApp app = new PlanetLabApp();
				boolean noSleep =false;
				if (args.length > 0) {
					if (args[0].equals("nosleep"))
						noSleep = true;
				}
				app.loadConfig(noSleep);
				app.displayConfig();
				app.runApp();
			} catch (Exception e) {
				e.printStackTrace();
			}
	}
	
}//end of PlanetLabApp
